package fr.cephb.operon.localcmd.snp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.regex.Pattern;

import com.sleepycat.db.DatabaseException;

import fr.cephb.joperon.core.Fid;
import fr.cephb.joperon.core.Operon;
import fr.cephb.joperon.core.bio.Assembly;
import fr.cephb.joperon.core.entities.SnpIds;
import fr.cephb.joperon.core.entities.SnpMap;
import fr.cephb.joperon.tool.OperonFactory;
import fr.cephb.operon.common.CmdLineApplication;

/**
 * Tool finding the position of the SNP from a list of snp Name
 * @author Pierre Lindenbaum
 *
 */
public class SnpFindLocByName01 extends CmdLineApplication
	{
	private Pattern RS_PATTERN= Pattern.compile("rs[0-9]+",Pattern.CASE_INSENSITIVE);
	/** assembly used */
	private Assembly assembly=null;
	
	
	public SnpFindLocByName01()
		{
		
		}
	
	private Assembly getAssembly() {
		return assembly;
		}
	
	
	public void run(File f)throws IOException
		{
		log().finest("Reading "+f);
		BufferedReader r= new BufferedReader(new FileReader(f));
		run(r);
		log().finest("End Read");
		}
	
	private void run(BufferedReader in) throws IOException
		{
		PrintWriter out= getWriter();
		Operon operon=null;
		OperonFactory factory=null;
		try {
			log().fine("Opering Operon with "+getBerkeleyDBHome());
			operon= Operon.newInstance(getBerkeleyDBHome());
			log().fine("Opering Factory of Databases");
			factory = new OperonFactory(operon);
			
			out.print("#");
			out.print("snp");
			out.print("\t");
			out.print("snp-id-count");
			out.print("\t");
			out.print("fid");
			out.print("\t");
			out.print("Chrom");
			out.print("\t");
			out.print("P");
			out.print("\t");
			out.print("Q");
			out.print("\t");
			out.print("Ctg");
			out.print("\t");
			out.print("Ori");
			out.print("\t");
			out.print("X");
			out.print("\t");
			out.print("Y");
			out.print("\t");
			out.print("Map-Weight");
			out.print("\t");
			out.print("Cat");
			out.print("\t");
			out.print("Ca");
			out.print("\t");
			out.print("Ra");
			out.print("\t");
			out.print("Aa");
			out.print("\t");
			out.print("Flags");
			
			out.println();
			
			String line;
			//loop over the line
			while((line=in.readLine())!=null)
				{
				line=line.trim();
				if(line.startsWith("#") || line.trim().length()==0 )
					{
					log().finest("Ignoring line "+line);
					continue;
					}
				String rsName= line.toLowerCase();
				log().finest(rsName);
				
				if(RS_PATTERN.matcher(rsName).matches()) rsName=rsName.toLowerCase();
				List<SnpIds> snpids=factory.getSnpIds(getAssembly()).get(rsName);
				if(snpids.isEmpty())
					{
					log().info(rsName+" not found");
					out.println("####NOT_FOUND:"+rsName);
					continue;
					}
				for(SnpIds snpid: snpids)
					{
					Fid fid=snpid.getFid();
					out.print(rsName);
					out.print("\t");
					out.print(snpids.size());
					out.print("\t");
					out.print(fid.asString());
					out.print("\t");
					SnpMap map= factory.getSnpMap(getAssembly()).get(fid);
					if(map==null)
						{
						log().info("No SnpMap for "+fid+" "+assembly);
						out.println("####NO_SNP_MAP");
						continue;
						}
					
					out.print(map.getChr());
					out.print("\t");
					out.print(map.getP());
					out.print("\t");
					out.print(map.getQ());
					out.print("\t");
					out.print(map.getCtg());
					out.print("\t");
					out.print(map.getOrientation());
					out.print("\t");
					out.print(map.getX());
					out.print("\t");
					out.print(map.getY());
					out.print("\t");
					out.print(map.getMw());
					out.print("\t");
					out.print(map.getCategory());
					out.print("\t");
					out.print(map.getCa());
					out.print("\t");
					out.print(map.getRa());
					out.print("\t");
					out.print(map.getAa());
					out.print("\t");
					out.print(map.getFlags());
					
					out.println();
					}
				
				}
			} 
		catch (IOException e) {
			throw e;
			}
		catch (DatabaseException e) {
			throw new IOException(e);
			}
		finally
			{
			log().fine("Closing Factory");
			if(factory!=null) factory.close();
			log().fine("Closing Operon");
			if(operon!=null) operon.safeClose();
			out.flush();
			}
		}
	
	
	@Override
	protected void usage(PrintStream out) {
		out.println("Author: Pierre Lindenbaum PhD.");
		out.println("Reads a delimited file of SNP and echo information of mapping.");
		super.usage(out);
		out.println(" -a <assemby-id> default:"+Assembly.getDefaultAssembly().getId());
		for(Assembly as: Assembly.getAssemblies())
			{
			out.println("   "+as.getId()+" : "+as.getName());
			}
		}
	
	
	@Override
	protected int parseOption(String[] args, int optind)
		{
		int i= super.parseOption(args, optind);
		if(i!=-1) return i;
		//assembly
		if(args[optind].equals("-a"))
			{
			this.assembly= Assembly.getAssemblyById(Integer.parseInt(args[++optind]));
			}
		else
			{
			return -1;
			}
		return optind;
		}
	
	/** main entry for this program */
	public static void main(String[] args)
		{
		try {
			SnpFindLocByName01 app= new SnpFindLocByName01();
			int optind=0;
			int index=0;
			//loop over arguments
		    while(optind<args.length)
				{
				if((index=app.parseOption(args,optind))!=-1)
				 	{
					optind= index; 
				 	}
				 else if (args[optind].equals("--"))
				     {
				     ++optind;
				     break;
				     }
				else if (args[optind].startsWith("-"))
				     {
				     System.err.println("bad argument " + args[optind]);
				     System.exit(-1);
				     }
				else
				     {
				     break;
				     }
				++optind;
				}
		    //check assembly
		    if(app.assembly==null)
		    	{
		    	app.assembly= Assembly.getDefaultAssembly();
		    	app.log().info("Set assembly to "+app.assembly);
		    	}
		    
		    //read from stdin
		    if(optind==args.length)
		    	{
		    	app.log().finest("Reading from Stdin");
		    	app.run(new BufferedReader(new InputStreamReader(System.in)));
		    	}
		    else
		    	{
		    	app.log().finest("Looping over Files");
		    	//loop over files
		    	while(optind< args.length)
		    		{
		    		BufferedReader r=null;
		    		try
		    			{
		    			app.run(new File(args[optind++]));
		    			}
		    		catch (IOException e) {
						throw e;
						}
		    		finally
		    			{
		    			if(r!=null) r.close();
		    			}
		    		}
		    	}
		    app.log().finest("Done.");
			}
		catch (Exception e)
			{
			e.printStackTrace();
			}
		}
	}
